#pragma once
#include<iostream>
#include<vector>
#include <string>
#include <queue>
#include <pthread.h>
#include <unistd.h>
using namespace std;

struct ThreadInfo{
	pthread_t tid;
	string name;
};

static const int defaultnum=5;

template<class T>
class ThreadPool
{
	public:
		void Lock()
		{
			pthread_mutex_lock(&_mutex);
		}
		void Unlock()
		{
			pthread_mutex_unlock(&_mutex);
		}
		void Wakeup()
		{
			pthread_cond_signal(&_cond);
		}
		void ThreadSleep()
		{
			pthread_cond_wait(&_cond,&_mutex);	
		}
		bool IsEmpty()
		{
			return _tasks.empty();
		}
		string GetThreadName(pthread_t tid)
		{
			for(const auto &ti:_threads)
			{
				if(ti.tid==tid) return ti.name;
			}
			return "None";
		}


	public:
		static void* Handler(void *args)
		{
			ThreadPool<T>*tp=static_cast<ThreadPool<T>*>(args);
			string name=tp->GetThreadName(pthread_self());
			while(true)
			{
				tp->Lock();
				while(tp->IsEmpty())
				{
					tp->ThreadSleep();
				}
				T t=tp->Pop();
				tp->Unlock();
				t();
				cout<<name<<"run,"
					<<"result:"<<t.GetRsult()<<endl;
			}
		}
		void Start()
		{
			int num=_threads.size();
			for(int i=0;i<num;i++)
			{
				_threads[i].name="thread"+to_string(i+1);
				pthread_create(&(_threads[i].tid),nullptr,Handler,this);

			}
		}
		T Pop()
		{	
			T t=_tasks.front();
			_tasks.pop();
			return t;
		}
		void Push(const T& t)
		{
			Lock();
			_tasks.push(t);
			Wakeup();
			Unlock();
		}

		static ThreadPool<T> * GetInstance()
		{
			if(nullptr==_ptr)
			{
				pthread_mutex_lock(&_lock);
				if(nullptr==_ptr)
				{
				cout<<"log:Creat done first!"<<endl;
				_ptr=new ThreadPool<T>();
				}
				pthread_mutex_unlock(&_lock);
			}
			return _ptr;

		}
	private:
		ThreadPool(int num=defaultnum):_threads(num)
	{
	pthread_mutex_init(&_mutex,nullptr);
	pthread_cond_init(&_cond,nullptr);
	}
	~ThreadPool()
	{
		pthread_mutex_destroy(&_mutex);
       		 pthread_cond_destroy(&_cond);
	//	pthread_mutex_destory(&_mutex);
	//	pthread_cond_destory(&_cond);
	}
	ThreadPool(const ThreadPool<T>&)=delete;
	const ThreadPool<T>& operator=(const ThreadPool<T>&)=delete;	
	private:
		vector<ThreadInfo> _threads;
		queue<T> _tasks;
		pthread_mutex_t  _mutex;
		pthread_cond_t  _cond;
		static ThreadPool<T>*_ptr;
		static pthread_mutex_t _lock;
};

template <class T>
ThreadPool<T>* ThreadPool<T>::_ptr=nullptr;
template<class T>
pthread_mutex_t ThreadPool<T>:: _lock=PTHREAD_MUTEX_INITIALIZER;
